#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "mitar.h"

extern char *uso;
char error[81];


int copynFile(FILE *origen, FILE *destimo, int nBytes);
int readHeader(FILE *tarFile, stHeaderEntry **header, int *nFiles);

int createTar(int nFiles, char *fileNames[], char tarName[]) {
  
  int i,c;
  FILE *tarFile, *inputFile;
  stHeaderEntry *header;
  
  //fichero[s]
  if(nFiles<=0) {
    fprintf(stderr, uso);
    return(EXIT_FAILURE);
  }

  //Abrimos el fichero destino
  tarFile=fopen(tarName,"w");
  if(tarFile==NULL){
	  perror(error);
	  return(EXIT_FAILURE);
  }

  //Reservamos memoria para la estructura cabecera del mtar
  header=(stHeaderEntry*)malloc(sizeof(stHeaderEntry)*nFiles);
  
  //Nos posicionamos enla zona de datos del fichero mtar
  fseek(tarFile,sizeof(int)+(sizeof(stHeaderEntry)*nFiles),SEEK_SET);

  //Relleno la cabecera en RAM y copio los datos de los ficheros en el tar
  for(i=0; i<nFiles; i++) {

	//Abrimos fichero fuente
	inputFile=fopen(fileNames[i],"r");
	if(inputFile==NULL){
		perror(error);
		return(EXIT_FAILURE);
	}

    //Completamos la cabecera en memoria (NO en el fichero)
	strcpy(header[i].name,fileNames[i]);

	//Copiamos el fichero origen al fichero TAR
	header[i].size=copynFile(inputFile,tarFile,999999);

	fclose(inputFile);

  }

  // Escribimos al fichero la cabecera (num. ficheros y lo que hemos ido creando en memoria)
  fseek(tarFile,0,SEEK_SET);

  fwrite(&nFiles,sizeof(int),1,tarFile);
  fwrite(header,sizeof(stHeaderEntry),nFiles,tarFile);

  fclose(tarFile);

  free(header);

  return(EXIT_SUCCESS);
}

int extractTar(char tarName[]) {
  stHeaderEntry *header;
  int nFiles,i;
  FILE *tarFile,*outputFile;
  
  //Abrimos el tarball
  tarFile=fopen(tarName,"r");
  if(tarFile==NULL){
	  perror(error);
	  return(EXIT_FAILURE);
  }
  //Leemos la cabecera del mtar, utilizando la funci�n readHeader
  readHeader(tarFile,&header,&nFiles);

  fseek(tarFile,sizeof(int)+(sizeof(stHeaderEntry)*nFiles),SEEK_SET);

  //Creamos los ficheros contenidos en el mtar. Para ello recorremos secuencialmente la cabecera,
  // creando (abriendo en escritura) los ficheros indicados en cada uno de los descriptores y copiando
  // en ellos su contenido, que se leer� del tarball usando la funci�n copynFile.
  for(i=0; i<nFiles; i++) {

	  //abrimos el fichero destino
	  outputFile=fopen(header[i].name,"w");
	  if(outputFile==NULL){
	  	  perror(error);
	  	  return(EXIT_FAILURE);
	  }

	  //copiamos el contenido original del archivo
	  copynFile(tarFile,outputFile,header[i].size);

	  //cerramos el fichero(comentado porque da error del heap¿?)
	  fclose(outputFile);

  }
  
  //Liberamos memoria de la cabecera y cerramos el tarball
  free(header);
  fclose(tarFile);
 
  return(EXIT_SUCCESS);
}
  
int copynFile(FILE *origen, FILE *destimo, int nBytes){
  int nCopy=0;
  char c;

  // Copiar todo el contenido del fichero origen, byte a byte, al destino.
  // Devolvemos en nCopy los bytes copiados.

  while(fread(&c,1,1,origen) && nCopy!=nBytes){

  	  putc(c,destimo);
  	  nCopy++;

  }

  //devuelvo el puntero a la anterior posicion
  fseek(origen,-1,SEEK_CUR);

  return(nCopy);
}

int readHeader(FILE *tarFile, stHeaderEntry **header, int *nFiles){

  //Primero leemos el n�mero de ficheros contenidos en el tarball
  fread(nFiles,sizeof(int),1,tarFile);

  //Reservamos memoria del heap para la cabecera del tarball
  *header=(stHeaderEntry*)malloc(sizeof(stHeaderEntry)**nFiles);

  //Leemos toda la cabecera
  fread(*header,sizeof(stHeaderEntry)**nFiles,*nFiles,tarFile);

  return(EXIT_SUCCESS);
}

int appendnewTar(int nFiles, char *fileNames[ ], char tarName[ ], char newtarName[ ]){

	FILE *nuevoTar,*viejoTar,*inputFile;
	stHeaderEntry *header,*header2;
	int oldFiles,i,totalFiles;

	//abrimos el antiguo tar y el nuevo
	nuevoTar=fopen(newtarName,"w");
	viejoTar=fopen(tarName,"r");
	if(nuevoTar==NULL || viejoTar==NULL){
		  perror(error);
		  return(EXIT_FAILURE);
	}

	//sacamos el header del antiguo tar
	readHeader(viejoTar,&header,&oldFiles);

	//calculamos los ficheros totales que hay
	totalFiles=oldFiles+nFiles;

	//aumentamos memoria para la cabecera
	header=(stHeaderEntry*)realloc(header,(sizeof(stHeaderEntry)*oldFiles)+(sizeof(stHeaderEntry)*nFiles));

	//situamos el puntero del antiguo tar dejando el espacio de la cabecera
	//y lo mismo con el nuevo tar y su cabecera ampliada
	//y copiamos de uno a otro la informacion
	fseek(viejoTar,sizeof(int)+(sizeof(stHeaderEntry)*oldFiles),SEEK_SET);
	fseek(nuevoTar,sizeof(int)+(sizeof(stHeaderEntry)*oldFiles)+(sizeof(stHeaderEntry)*nFiles),SEEK_SET);
	copynFile(viejoTar,nuevoTar,9999999);


	//recorrremos los nuevos ficheros y vamos rellenando la informacion de la cabecera y
	//copiandolo al nuevo tar
	for(i=oldFiles; i<totalFiles; i++) {

		//Abrimos fichero fuente
		inputFile=fopen(fileNames[i-oldFiles],"r");
		if(inputFile==NULL){
			perror(error);
			return(EXIT_FAILURE);
		}
	    //Completamos la cabecera en memoria (NO en el fichero)
		strcpy(header[i].name,fileNames[i-oldFiles]);

		//Copiamos el fichero origen al fichero TAR
		header[i].size=copynFile(inputFile,nuevoTar,999999);

		//cerramos el fichero(comentado porque da error del heap¿?)
		fclose(inputFile);

	}

	//escribimos la nueva cabecera en el nuevo tar
	fseek(nuevoTar,0,SEEK_SET);

	fwrite(&totalFiles,sizeof(int),1,nuevoTar);
	fwrite(header,sizeof(stHeaderEntry),totalFiles,nuevoTar);

	fclose(nuevoTar);

	free(header);

	return(EXIT_SUCCESS);

}

